#include "TeamManager.h"
#include "LeagueManager.h"
#include "PeopleManager.h"
#include "NameManager.h"
#include "ServiceProvider.h"
#include "GameSettings.h"
#include "RandomSystem.h"
#include "ZStream.h"
#include "Types.h"

#include <cassert>

int TeamManager::NUMBERS_OF_TEAMS = 0;

TeamManager::TeamManager(ServiceProvider* const i_sp)
:m_sp(i_sp)
{
	assert(i_sp);
}

TeamManager::~TeamManager()
{
	Clear();
}

void TeamManager::Clear()
{
	Utilities::DeepClear(m_teams);

	NUMBERS_OF_TEAMS = 0;
}

void TeamManager::Initialize()
{
	NUMBERS_OF_TEAMS = 0;

	Team::s_params.MAX_CHAR_TEAM_NAME = m_sp->GetSettings().GetValue("I_MAX_CHAR_TEAM_NAME").Get<size_t>();
	Team::s_params.STARTING_TEAM_PLAYERS = m_sp->GetSettings().GetValue("I_STARTING_TEAM_PLAYERS").Get<size_t>();
	Team::s_params.MAX_TEAM_PLAYERS		= m_sp->GetSettings().GetValue("I_MAX_TEAM_PLAYERS").Get<size_t>();
	Team::s_params.MIN_TEAM_PLAYERS		= m_sp->GetSettings().GetValue("I_MIN_TEAM_PLAYERS").Get<size_t>();

	Team::s_params.STARTING_TEAM_TRAINERS = m_sp->GetSettings().GetValue("I_STARTING_TEAM_TRAINERS").Get<size_t>();
	Team::s_params.MAX_TEAM_TRAINERS	= m_sp->GetSettings().GetValue("I_MAX_TEAM_TRAINERS").Get<size_t>();
	Team::s_params.MIN_TEAM_TRAINERS	= m_sp->GetSettings().GetValue("I_MIN_TEAM_TRAINERS").Get<size_t>();

	Team::s_params.TITOLARS_PLAYERS		= 5;
}

Team* TeamManager::CreateNewTeam()
{
	Team* newTeam = new Team(m_sp, m_sp->GetNameMgr().GetATeamName(), NUMBERS_OF_TEAMS++);
	m_teams.push_back(newTeam);
	return newTeam;
}

Team* TeamManager::GetTeam(const int i_teamID) const
{
	if(i_teamID == Utilities::INVALID_ID)
		return 0;
	assert(m_teams[i_teamID]->GetID() == i_teamID);
	return m_teams[i_teamID];
}

const STL::string& TeamManager::GetTeamName(const int i_teamID) const
{
	static const STL::string FreeTeamName = "--Free--";

	const Team* theTeam = GetTeam(i_teamID);
	if(theTeam)
		return theTeam->GetName();
	return FreeTeamName;
}

void TeamManager::Update() 
{
}

void TeamManager::EndSeasonUpdate(STD::stringstream& o_message)
{
	// Bankrupt Management

	bool noBankrupt = true;
	o_message << STD::endl << "TeamManager News:" << STD::endl << STD::endl;
	for (size_t i=0; i<m_teams.size(); ++i)
	{
		if(m_teams[i]->GetBudget() >= 0)
		{
			m_teams[i]->m_bankruptWarnings = 0;
			//small taxation of budget exceeding a fixed threshold
			const int NoTaxArea = 10000;
			if(m_teams[i]->m_budget > NoTaxArea)
				m_teams[i]->m_budget = NoTaxArea + ( 90 * (m_teams[i]->m_budget-NoTaxArea) / 100);
		}
		else
		{
			noBankrupt = false;
			++m_teams[i]->m_bankruptWarnings;
			const bool isBankrupt = m_teams[i]->m_bankruptWarnings == 3;
			if(isBankrupt)
			{
				//Handle Bankrupt!
				m_sp->GetLeagueMgr().HandleBankrupt(m_teams[i]); //LM move team in last layer and propagate teams substitution
				m_sp->GetPeopleMgr().HandleBankrupt(m_teams[i]); //PM renews players and trainers
				m_teams[i]->m_bankruptWarnings = 0;
				m_teams[i]->m_teamHistory.SetBankruptCount();
				o_message << "BANKRUPT for Team: " << m_teams[i]->GetName() << STD::endl;
			}
			else
			{
				o_message << "WARNING (" << m_teams[i]->m_bankruptWarnings << ") for Team: " << m_teams[i]->GetName() << STD::endl;
			}

			const LeagueSettings& ls = m_sp->GetLeagueMgr().GetSettings().m_layerSettings.back().leagueSettings;

			if(isBankrupt)  
				m_teams[i]->m_budget = RandIntBetween(ls.minStartingTeamBdg, ls.minStartingTeamBdg+ls.deltaStartingTeamBdg);
			else if(!m_teams[i]->IsUserControlled()) //little cheat for AI: reset economy after each warning, to help save financial situation
				m_teams[i]->m_budget = RandIntBetween(ls.minStartingTeamBdg, ls.minStartingTeamBdg+ls.deltaStartingTeamBdg)/4;
			else //little cheat for human player too ;)
				m_teams[i]->m_budget = 0;
		}

#ifndef DARIO
		if(!m_teams[i]->IsUserControlled())
		{
			m_teams[i]->CheckRenewContract(o_message);
		}
#endif
	}
	o_message << STD::endl << (noBankrupt ? "No Bankrupt News!" : "") << STD::endl << STD::endl;

}

ZStream& TeamManager::Serialize(ZStream& o_stream) const
{
	o_stream.WriteOpenTag("TeamsManager");

	assert(m_teams.size() == static_cast<size_t>(NUMBERS_OF_TEAMS));
	o_stream.WriteAttribute("TeamsNum", NUMBERS_OF_TEAMS);
	for (TeamVecCit it = m_teams.begin(); it != m_teams.end(); ++it)
		(*it)->Serialize(o_stream);
	
	o_stream.WriteCloseTag("TeamsManager");

	return o_stream;
}

ZStream& TeamManager::Deserialize(ZStream& i_stream)
{
	i_stream.SkipLine();

	//we assume we don't have to resize TeamManager because every game has the same unmber of teams (TODO: I don't like it!)
	i_stream.ReadAttribute(NUMBERS_OF_TEAMS);
	assert(m_teams.size() == static_cast<size_t>(NUMBERS_OF_TEAMS));
	for (TeamVecIt it = m_teams.begin(); it != m_teams.end(); ++it)
		(*it)->Deserialize(i_stream);

	i_stream.SkipLine();

	return i_stream;
}